package org.zfin.properties.ant;

import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.log4j.Logger;

import java.io.*;
import java.util.Iterator;

/**
 * Creates a file from loaded properties.
 *
 * Arguments:
 * - propertyFile (required)
 * - target (required)
 * - envPropertyFile  (optional:  list of properties to export.  default is export all to env).
 * - override  (optional: default is true)
 * -  header
 * -  keyPrefix
 * -  keySuffix
 * -  valuePrefix
 * -  valueSuffix
 * -  lineEnd ="\n"
 * -  footer
 * -  footerFile
 * -  suppressKey = false
 * -  suppressValue = false
 *
 * Search and replace for tokens @KEY@ @VALUE@ @COUNT@ @PROPERTY_FILE@ @EXPORT_FILE@ for all fields.
 */
public class ExportPropertiesTask extends PropertyFileTask {

    private final static Logger logger = Logger.getLogger(ExportPropertiesTask.class) ;

    private String target ;
    private String exportPropertyFile = null ;
    private String header ;
    private String headerFile ;
    private String keyPrefix ="";
    private String keySuffix = "";
    private String valuePrefix ="";
    private String valueSuffix ="" ;
    private String keyValueExpressionFile  ;
    private String lineEnd = "\n";
    private String footer ;
    private String footerFile;
    private boolean suppressKey = false ;
    private boolean suppressValue = false ;

    // filter tokens
    private final static String KEY_TOKEN = "@KEY@" ;
    private final static String VALUE_TOKEN = "@VALUE@" ;
    private final static String COUNT_TOKEN = "@COUNT@" ;
    private final static String PROPERTY_FILE_TOKEN = "@PROPERTY_FILE@" ;
    private final static String EXPORT_FILE_TOKEN = "@EXPORT_FILE@" ;


    public void execute() {
        BufferedWriter bufferedWriter = null ;
        try {
            logger.debug("From property file: "  + getFile());
            PropertiesConfiguration propertiesConfiguration = createPropertiesConfiguration();
            PropertiesConfiguration exportPropertiesConfiguration = null ;
            if(exportPropertyFile !=null){
                exportPropertiesConfiguration = new PropertiesConfiguration(exportPropertyFile);

            }

            File file = new File(target) ;
            logger.debug("Creating env file: "  +file.getAbsolutePath() );
            if(file.exists()){
                assert(file.delete());
            }

            int counter = 0 ;
            for(Iterator iterator = propertiesConfiguration.getKeys()  ; iterator.hasNext();   ){
                iterator.next() ;
                ++counter ;
            }

            bufferedWriter = new BufferedWriter(new FileWriter(file)) ;

            dumpFile(headerFile,bufferedWriter,counter) ;

            // write prefix
            if(header!=null) bufferedWriter.write(filterTokens(header,counter)+lineEnd) ;



            String keyValueExpression = null ;
            if(keyValueExpressionFile!=null){
                keyValueExpression = "" ;
                BufferedReader footerReader = new BufferedReader(new FileReader(keyValueExpressionFile));
                String line;
                while((line = footerReader.readLine()) != null) {
                    keyValueExpression += line + lineEnd ;
                }
                footerReader.close();
                if(footerReader!=null){
                    footerReader.close();
                }
            }

            String key ;
            for(Iterator iterator = propertiesConfiguration.getKeys();
                iterator.hasNext(); ){
                key = iterator.next().toString();
                if(exportPropertiesConfiguration==null || exportPropertiesConfiguration.getKeys(key).hasNext()){

                    if(keyValueExpression!=null){
                        bufferedWriter.write(
                                filterTokens(keyValueExpression,key,propertiesConfiguration,counter)) ;
                    }

                    // if suppress is false and either the prefix or suffix is not null
                    // then display
                    if( !suppressKey && (keyPrefix!=null || keySuffix!=null)){
                        bufferedWriter.write(
                                filterTokens(keyPrefix,key,propertiesConfiguration,counter) + key +
                                        filterTokens(keySuffix,key,propertiesConfiguration,counter)) ;
                    }

                    // if suppress is false and either the prefix or suffix is not null
                    // then display
                    if( !suppressValue && (valuePrefix!=null || valueSuffix!=null) ){
                        bufferedWriter.write(
                                filterTokens(valuePrefix,key,propertiesConfiguration,counter) +
                                        propertiesConfiguration.getString(key)+
                                        filterTokens(valueSuffix,key,propertiesConfiguration,counter)
                        ) ;
                    }

                    // if key or value is not suppressed
                    // or if the non-suppressed key or value does not have null values
                    if(  !(suppressKey || (keyPrefix==null && keySuffix==null))
                    || !(suppressValue || (valuePrefix==null && valueSuffix==null)) ) {
                        bufferedWriter.write( filterTokens(lineEnd,key,propertiesConfiguration,counter)) ;
                    }
                }
            }

            dumpFile(footerFile,bufferedWriter,counter) ;

            if(footer!=null) bufferedWriter.write(filterTokens(footer,counter));

            bufferedWriter.close();

        } catch (Exception e) {
            throw new RuntimeException("failed to load configuration",e);
        }
        finally{
            try {
                if(bufferedWriter!=null){
                    bufferedWriter.close();
                }
            } catch (IOException e) {
                logger.error(e);
            }
        }
    }

    private void dumpFile(String footerFile,BufferedWriter bufferedWriter,int counter) throws IOException{
        if (footerFile != null) {
            BufferedReader footerReader = new BufferedReader(new FileReader(footerFile));
            String line;
            while((line = footerReader.readLine()) != null) {
                bufferedWriter.write(filterTokens(line,counter)+ lineEnd);
            }
        }
    }

    private String filterTokens(String unfilteredString, int count) {
        String returnString = unfilteredString ;
        returnString = returnString.replaceAll(COUNT_TOKEN,String.valueOf(count)) ;
        returnString = returnString.replaceAll(PROPERTY_FILE_TOKEN, getFile()) ;
        if(exportPropertyFile!=null){
            returnString = returnString.replaceAll(EXPORT_FILE_TOKEN,exportPropertyFile) ;
        }
        return returnString ;
    }

    private String filterTokens(String unfilteredString,String key,PropertiesConfiguration propertiesConfiguration,int count){
        String returnString = filterTokens(unfilteredString,count) ;
        returnString = returnString.replaceAll(KEY_TOKEN,key) ;
        returnString = returnString.replaceAll(VALUE_TOKEN,propertiesConfiguration.getString(key)) ;
        return returnString ;
    }

    public void setTarget(String target) {
        this.target = target;
    }

    public void setExportPropertyFile(String exportPropertyFile) {
        this.exportPropertyFile = exportPropertyFile;
    }

    public void setHeader(String header) {
        this.header = header;
    }

    public String getHeaderFile() {
        return headerFile;
    }

    public void setHeaderFile(String headerFile) {
        this.headerFile = headerFile;
    }

    public void setKeyPrefix(String keyPrefix) {
        this.keyPrefix = keyPrefix;
    }

    public void setKeySuffix(String keySuffix) {
        this.keySuffix = keySuffix;
    }

    public void setValuePrefix(String valuePrefix) {
        this.valuePrefix = valuePrefix;
    }

    public void setValueSuffix(String valueSuffix) {
        this.valueSuffix = valueSuffix;
    }

    public String getKeyValueExpressionFile() {
        return keyValueExpressionFile;
    }

    public void setKeyValueExpressionFile(String keyValueExpressionFile) {
        this.keyValueExpressionFile = keyValueExpressionFile;
    }

    public void setLineEnd(String lineEnd) {
        this.lineEnd = lineEnd;
    }

    public void setFooter(String footer) {
        this.footer = footer;
    }

    public String getFooterFile() {
        return footerFile;
    }

    public void setFooterFile(String footerFile) {
        this.footerFile = footerFile;
    }

    public boolean isSuppressKey() {
        return suppressKey;
    }

    public void setSuppressKey(boolean suppressKey) {
        this.suppressKey = suppressKey;
    }

    public boolean isSuppressValue() {
        return suppressValue;
    }

    public void setSuppressValue(boolean suppressValue) {
        this.suppressValue = suppressValue;
    }

    public void setSuppressKeyValue(boolean suppressValue){
        setSuppressKey(suppressValue);
        setSuppressValue(suppressValue);
    }
}